package gin

import (
	io_gin "clean/adapter/io/http/gin"
	"clean/infra/config"
	"clean/infra/io"
	"clean/infra/io/driver"
	"clean/usecase"
	"context"
	"errors"
	"github.com/gin-gonic/gin"
	"github.com/oklog/run"
	"net/http"
	"os"
	"strconv"
	"time"
)


type ioDriver struct {
}

func init() {
	io.Register("http_gin", &ioDriver{})
}

func (ioDriver) Create(cfg config.Config, app usecase.Input) (io_driver.Io, error) {
	return NewServerGin(cfg, app)
}


// https://gin-gonic.com/zh-cn/
type ServerGin struct {
	*gin.Engine
	port int
}

func NewServerGin(cfg config.Config, app usecase.Input) (*ServerGin, error) {
	gin.SetMode(cfg.Io.Http.Gin.GinMode)
	e := gin.New()
	e.Use(gin.Recovery())

	h := io_gin.NewHandler(app)
	h.Init(e)

	s := &ServerGin{
		Engine: e,
		port:   cfg.Io.Http.Gin.Port,
	}
	return s, nil
}

func (s *ServerGin) Start() error {
	var g run.Group
	srv := &http.Server{
		Addr:    ":" + strconv.Itoa(s.port),
		Handler: s,
	}
	var shutDownErr error
	g.Add(func() error {
		if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			return err
		}
		return nil
	}, func(e error) {
		ctx, _ := context.WithTimeout(context.Background(), 5*time.Second)
		shutDownErr = srv.Shutdown(ctx)
	})
	g.Add(run.SignalHandler(context.Background(), os.Interrupt))
	err := g.Run()
	if shutDownErr != nil {
		return shutDownErr
	}
	if err == nil || errors.As(err, &run.SignalError{}) {
		return nil
	}
	return err
}
